/**********************************************************************************************************************
 *
 * Project:    mGameEngine
 * File:       color.h
 * Author:     karooolek
 * Created on: 2009-01-05
 *
 **********************************************************************************************************************/

#ifndef COLOR_H_
#define COLOR_H_

namespace mGameEngine
{

/**
 * RGBA color.
 * Components are stored as floating point numbers.
 * They are not clamped to 0.0 - 1.0.
 */
struct Color
{
    union
    {
        /**
         * Color components.
         */
        float v[4];

        /**
         * R, G, B, A color components.
         */
        struct
        {
            float r, g, b, a;
        };
    };

    /**
     * Create color with initial values.
     * @param r red component.
     * @param g green component.
     * @param b blue component.
     * @param a alpha component.
     */
    Color(float r = 0.0f, float g = 0.0f, float b = 0.0f, float a = 1.0f) :
        r(r), g(g), b(b), a(a)
    {
    }

    /**
     * Create color with initial values.
     * @param v floats array.
     */
    Color(const float *v) :
        r(v[0]), g(v[1]), b(v[2]), a(v[3])
    {
    }

    /**
     * Create color with initial values.
     * @param r red component.
     * @param g green component.
     * @param b blue component.
     * @param a alpha component.
     */
    Color(uint8 r, uint8 g, uint8 b, uint8 a = 255) :
        r(r/255.0f), g(g/255.0f), b(b/255.0f), a(a/255.0f)
    {
    }

    /**
     * Create color with initial values.
     * @param v bytes array.
     */
    Color(const uint8 *v) :
        r(v[0]/255.0f),    g(v[1]/255.0f),    b(v[2]/255.0f),    a(v[3]/255.0f)
    {
    }

    /**
     * Copy constructor.
     * @param c color to copy.
     */
    Color(const Color &c) :
        r(c.r), g(c.g), b(c.b), a(c.a)
    {
    }

    /**
     * Assign color.
     * @param c color to assign.
     * @return color with assigned value.
     */
    Color &operator=(const Color &c)
    {
        r = c.r;    g = c.g;    b = c.b;    a = c.a;
        return *this;
    }

    /**
     * Add color.
     * @param c color to add
     * @return increased color
     */
    Color &operator+=(const Color &c)
    {
        r += c.r;    g += c.g;    b += c.b;    a += c.a;
        return *this;
    }

    /**
     * Add colors.
     * @param c color to add
     * @return sum of colors
     */
    Color operator+(const Color &c) const
    {
        return Color(r + c.r, g + c.g, b + c.b, a + c.a);
    }

    /**
     * Decrease color.
     * @param c color to subtract
     * @return decreased color
     */
    Color &operator-=(const Color &c)
    {
        r -= c.r;    g -= c.g;    b -= c.b;    a -= c.a;
        return *this;
    }

    /**
     * Subtract colors.
     * @param c color to subtract
     * @return difference of colors
     */
    Color operator-(const Color &c) const
    {
        return Color(r - c.r, g - c.g, b - c.b, a - c.a);
    }

    /**
     * Multiply by scalar.
     * @param a scalar multiplier
     * @return multiplied color
     */
    Color &operator*=(float a)
    {
        r *= a;    g *= a;    b *= a;    Color::a *= a;
        return *this;
    }

    /**
     * Multiply color by scalar.
     * @param a scalar multiplier.
     * @return multiplied color.
     */
    Color operator*(float a) const
    {
        return Color(r * a, g * a, b * a, Color::a * a);
    }

    /**
     * Multiply scalar by color.
     * @param a scalar.
     * @param c color.
     * @return multiplied color and scalar.
     */
    friend Color operator*(float a, const Color &c)
    {
        return c * a;
    }

    /**
     * Multiply by color (component-wise).
     * @param c multiplier.
     * @return multiplied color.
     */
    Color &operator*=(const Color &c)
    {
        r *= c.r;    g *= c.g;    b *= c.b;    a *= c.a;
        return *this;
    }

    /**
     * Multiply colors (component-wise).
     * @param c multiplier.
     * @return multiplied colors.
     */
    Color operator*(const Color &c) const
    {
        return Color(r * c.r, g * c.g, b * c.b, a * c.a);
    }

    /**
     * Divide by scalar.
     * @param a scalar divisor
     * @return divided color
     */
    Color &operator/=(float a)
    {
        r /= a;    g /= a;    b /= a;    Color::a /= a;
        return *this;
    }

    /**
     * Divide by scalar.
     * @param a scalar divisor.
     * @return divided color.
     */
    Color operator/(float a) const
    {
        return Color(r / a, g / a, b / a, Color::a / a);
    }

    /**
     * Divide by color (component-wise).
     * @param c divisor.
     * @return divided color.
     */
    Color &operator/=(const Color &c)
    {
        r /= c.r;    g /= c.g;    b /= c.b;    a /= c.a;
        return *this;
    }

    /**
     * Divide colors (component-wise).
     * @param c divisor
     * @return divided colors.
     */
    Color operator/(const Color &c) const
    {
        return Color(r / c.r, g / c.g, b / c.b, a / c.a);
    }

    /**
     * Colors equal.
     * @param c color to compare
     * @return true if all components equal
     */
    bool operator==(const Color &c) const
    {
        return r == c.r && g == c.g && b == c.b && a == c.a;
    }

    /**
     * Vectors differ.
     * @param c color to compare
     * @return true if any off components differs
     */
    bool operator!=(const Color &c) const
    {
        return r != c.r || g != c.g || b != c.b || a != c.a;
    }

    /**
     * Floats array cast.
     * @return floats array
     */
    operator float *()
    {
        return v;
    }

    /**
     * Floats const array cast.
     * @return floats const array
     */
    operator const float *() const
    {
        return v;
    }
};

}

#endif // COLOR_H_
